using System;
using System.Web;
using System.Configuration;
using System.Net.Mail;

namespace GoodStuff.Diagnostics
{
	/// <summary>
	/// De ErrorMailSender module sends an e-mail on every Exception in the running asp.Net webapplication
	/// </summary>
	/// <example>
	/// Add the following &lt;appSettings&gt; to the &lt;configuration&gt; sectie
    /// &lt;add key="ExceptionMailerFrom"       value="sender@mail.com"/&gt;
    /// &lt;add key="ExceptionMailerRecipients  value="person1@mail.com;person2@mail.com"/&gt;
    /// &lt;add key="ExceptionMailerSmtpServer" value="smtp.mail.nl"/&gt; &lt;-- optional
    ///
    /// &lt;httpModules&gt;
    /// 	&lt;add type="GoodStuff.Diagnostics.ExceptionMailer, GoodStuff" name="ExceptionMailer"/&gt;
    /// &lt;/httpModules&gt;
	/// </example>
    [Obsolete("Please switch to the ExceptionHandlerModule for extended features")]
	public class ExceptionMailer : IHttpModule
	{
        //config keys
        private const string _fromAppKey        = "ExceptionMailerFrom";
        private const string _recipientsAppKey  = "ExceptionMailerRecipients";
        private const string _smtpAppKey        = "ExceptionMailerSmtpServer";
        
        //config values
        private static bool _checkConfiguration = true;
        private static string _valueFrom = null;
        private static string _valueSmtp = null;
        private static string _valueRecipients = null;

		#region IHttpModule Members

		public void Init(HttpApplication context)
		{
            context.BeginRequest += new EventHandler(context_BeginRequest);
			context.Error += new EventHandler(context_Error);
		}

		public void Dispose()
		{
			// TODO:  Add ErrorHandler.Dispose implementation
		}

		#endregion

        private void ReadConfig()
        {
            //Check if required appSettings are configured. We do this on begin_request, so directly after
            //this module has been configured the app stops running because of missing appSettings :)

            //SMTP server can also be configured through the default system.net/mailSettings/Network section in the web.config
            //Only throw an error when this section and the appSetting is missing
            //FROM can also be configured through the default system.net/mailSettings section in the web.config
            //Only throw an error when this section and the appSetting is missing

            System.Configuration.Configuration config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
            System.Net.Configuration.MailSettingsSectionGroup settings = (System.Net.Configuration.MailSettingsSectionGroup)config.GetSectionGroup("system.net/mailSettings");
            bool fromConfigured = false;
            bool smtpConfigured = false;
            if (settings != null && settings.Smtp != null)
            {
                fromConfigured = !string.IsNullOrEmpty(settings.Smtp.From);
                if (fromConfigured)
                {
                    //save value;
                    _valueFrom = settings.Smtp.From;
                }

                if (settings.Smtp.Network != null)
                {
                    smtpConfigured = !string.IsNullOrEmpty(settings.Smtp.Network.Host);

                    if (smtpConfigured)
                    {
                        //save value;
                        _valueSmtp = settings.Smtp.Network.Host;
                    }
                }
            }

            if (fromConfigured == false)
            {
                if (string.IsNullOrEmpty(ConfigurationManager.AppSettings[_fromAppKey]))
                    throw new ConfigurationErrorsException(string.Format("ExceptionMailer-Module; a required AppSetting with key {0} is not configured.  (or configure the section : system.net/mailSettings/From) within your configuration.", _fromAppKey));
                else
                    _valueFrom = ConfigurationManager.AppSettings[_fromAppKey];
            }

            if (smtpConfigured == false)
            {
                if (string.IsNullOrEmpty(ConfigurationManager.AppSettings[_smtpAppKey]))
                    throw new ConfigurationErrorsException(string.Format("ExceptionMailer-Module; a required AppSetting with key {0} is not configured. (or configure the section : system.net/mailSettings/Network/Smtp/Host) within your configuration.", _smtpAppKey));
                else
                    _valueSmtp = ConfigurationManager.AppSettings[_smtpAppKey];
            }

            if (string.IsNullOrEmpty(ConfigurationManager.AppSettings[_recipientsAppKey]))
                throw new ConfigurationErrorsException(string.Format("ExceptionMailer-Module; a required AppSetting with key {0} is not configured.", _recipientsAppKey));
            else
                _valueRecipients = ConfigurationManager.AppSettings[_recipientsAppKey];

            //If we are still here, everything is configured OK. Since a change in configuration will recycle the appPool and will reset
            //all static properties, we remember that we've performed this configchecks. Configuration changed? -> _checkConfiguration will be true again.
            //The same applies for the value we saved in static properties.
            _checkConfiguration = false;
        }

        private void context_BeginRequest(object sender, EventArgs e)
        {
            if (_checkConfiguration)
            {
                ReadConfig();
            }
        }

		private void context_Error(object sender, EventArgs e)
		{
			try
			{
				HttpApplication app = (HttpApplication)sender;
				Exception error = app.Server.GetLastError();

				LogException(error, HttpContext.Current.Request);
			}
			catch(Exception exception)
			{
				System.Diagnostics.Trace.WriteLine("Error while mailing exception: " + exception.ToString());
			}
		}

		private void LogException(Exception error, HttpRequest Request)
		{
            if (_checkConfiguration == true
                    || string.IsNullOrEmpty(_valueFrom)
                    || string.IsNullOrEmpty(_valueSmtp)
                    || string.IsNullOrEmpty(_valueRecipients))
            {
                ReadConfig(); //re-read config
            }

			//send Email to support
            MailMessage msg = new MailMessage();

			string subject = error.InnerException != null? error.InnerException.Message : error.Message;
            if (subject != null && subject.IndexOf("\r\n") > 0)
            {
                //subject contains newlines, take the first one.
                subject = subject.Split(new char[] { '\r', '\n' })[0];
            }
            if (subject != null && subject.Length > 128)
            {
                subject = subject.Substring(0, 128) + "...";
            }

			msg.Subject = "[" + Request.Url.Host + "] : " + subject;
            msg.From = new MailAddress(_valueFrom);
            msg.IsBodyHtml = false;

            string[] toSplitted = _valueRecipients.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string to in toSplitted)
            {
                msg.To.Add(to);
            }
			
			msg.Body = String.Format(
				"Exception: {0}\n\n"
				+ "Inner exception: {1}\n\n"
				+ "Url: {2}\n\n"
				+ "User: {3}\n\n"
				+ "Details:\n{4}",
				
				error.Message,
				error.InnerException != null? error.InnerException.Message : "null",
				Request.Url.ToString(), 
				Request.UserHostAddress + " (" + Request.UserAgent + ")",
				error);

            SmtpClient smtp = new SmtpClient(_valueSmtp);
            smtp.Send(msg);
		}
	}
}
